package top.infopub.mgc.util;


import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * 功能说明：pdf文档转图片
 * @author Awoke
 * @version 2018年6月28日
 * @see PdfToImageUtil
 * @since
 */
public final class PdfToImageUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(PdfToImageUtil.class);

    /**
     * pdf合并成一张png，转成的同路径同名的图片 并返回图片的二进制文件流 
     * @param srcFile pdf转换源文件
     * @return 
     * @see
     */
    public static byte[] pdfToImage(String srcFile) {
        return pdfToImage(srcFile, "", "png", 150F);
    }

    /**
     * pdf转图片
     * @param srcFile pdf转换源文件
     * @param destPath 图片输出目标路径，为空时默认源文件所在的文件夹
     * @param format 待输出图片的格式，默认png
     * @param dpi 分辨率，默认96
     */
    public static byte[] pdfToImage(String srcFile, String destPath, String format, Float dpi) {
        FileInputStream fis = null;
        try {
            File file = new File(srcFile);
            // 默认输出路径为源文件所在文件夹
            if (StringUtils.isBlank(destPath)) {
                destPath = file.getParent();
            }
            // 默认为png
            format = (StringUtils.isBlank(format) ? "png" : format);
            String pdfFileName = file.getName();
            pdfFileName = pdfFileName.substring(0, pdfFileName.indexOf('.'));
            // pdf file
            StringBuilder fileImagePath = new StringBuilder();
            fileImagePath.append(destPath).append(File.separator).append(pdfFileName).append(".").append(
                format);
            File imageFile = new File(fileImagePath.toString());
            // 文件已经存在 且 pdf没有在png生成后 有过修改  则直接返回
            if (imageFile.exists() && (imageFile.lastModified() > file.lastModified())) {
                fis = new FileInputStream(fileImagePath.toString());
                int size = fis.available();
                byte[] buffer = new byte[size];
                IOUtils.read(fis, buffer);
                return buffer;
            }
            // 转成image
            List<BufferedImage> images = pdfToImage(file, (dpi == null ? 96F : dpi));
            if (CollectionUtils.isEmpty(images)) {
                return null;
            }
            // 合并多张图片为一张
            BufferedImage image = mergeImages(images);
            images.clear();
            images.add(image);
            // 保存到本地
            for (int i = 0, len = images.size(); i < len; i++ ) {
                ImageIO.write(images.get(i), format, imageFile);
            }
            fis = new FileInputStream(fileImagePath.toString());
            int size = fis.available();
            byte[] buffer = new byte[size];
            IOUtils.read(fis, buffer);
            return buffer;
        }
        catch (Exception e) {
            LOGGER.error("pdfToImage error", e);
        }
        finally {
            IOUtils.closeQuietly(fis);
        }
        return null;
    }

    /**
     * 合并多张图片到一张图片
     * @param images
     * @return 
     * @see
     */
    private static BufferedImage mergeImages(List<BufferedImage> images) {
        int width = 0;
        int height = 0;
        for (BufferedImage image : images) {
            width = (image.getWidth() > width ? image.getWidth() : width);
            height += image.getHeight();
        }
        BufferedImage pdfImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = pdfImage.createGraphics();
        height = 0;
        for (BufferedImage image : images) {
            g2d.drawImage(image, (width - image.getWidth()) / 2, height, image.getWidth(),
                image.getHeight(), null);
            height += image.getHeight();
        }
        g2d.dispose();
        return pdfImage;
    }

    /**
     * pdf转成图片
     * @param file
     * @param dpi
     * @return
     * @throws IOException 
     * @see
     */
    private static List<BufferedImage> pdfToImage(File file, float dpi)
        throws IOException {
        List<BufferedImage> imgList = null;
        PDDocument pdDocument = null;
        BufferedImage image;
        try {
            pdDocument = PDDocument.load(file);
            PDFRenderer renderer = new PDFRenderer(pdDocument);
            int numPages = pdDocument.getNumberOfPages();
            imgList = new ArrayList<BufferedImage>();
            for (int i = 0; i < numPages; i++ ) {
                image = renderer.renderImageWithDPI(i, dpi);
                if (null != image) {
                    imgList.add(image);
                }
            }
        }
        catch (IOException e) {
            LOGGER.error("convert pdf pages to images failed.", e);
            throw e;
        }
        finally {
            IOUtils.closeQuietly(pdDocument);
        }
        return imgList;
    }

    /**
     * TEST
     * @param args 
     * @see
     */
    public static void main(String[] args) {
        // 1552735
        System.out.println(pdfToImage("D:/opt/abs/pdf/38E9FBF1B3264E93BA18D3162EBFFC78/sign/1.pdf").length);
    }

}